/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* includes (local) ----------------------------------------------------------*/
#include "vfs_mockfs.h"
#include <vfs.h>
/* includes (standard library, system) ---------------------------------------*/
#include <fcntl.h>    // open
#include <unistd.h>   // close, read, write, lseek, fsync
#include <sys/ioctl.h>
#include <dirent.h>     // opendir, readdir, closedir
#include <sys/stat.h>   // stat, mkdir, rmdir
#include <stdio.h>      // rename
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/

/* defines -------------------------------------------------------------------*/
/* typedefs ------------------------------------------------------------------*/
/* macro ---------------------------------------------------------------------*/
/* variables (extern) --------------------------------------------------------*/
/* variables (local) ---------------------------------------------------------*/
/* variables (global) --------------------------------------------------------*/
/* inlines -------------------------------------------------------------------*/
/* functions -----------------------------------------------------------------*/

static int mockfs_op_open(struct file *fp, const char *path, int flags, int mode)
{
    int fd = open(path, flags, mode);
    if (fd < 0) {
        return -1;
    }
    fp->fl_data = (uintptr_t)fd;
    return 0;
}

static int mockfs_op_close(struct file *fp)
{
    return close((int)fp->fl_data);
}

static int mockfs_op_read(struct file *fp, char *buf, size_t nbyte)
{
    return read((int)fp->fl_data, buf, nbyte);
}

static int mockfs_op_write(struct file *fp, const char *buf, size_t nbyte)
{
    return write((int)fp->fl_data, buf, nbyte);
}

static int mockfs_op_lseek(struct file *fp, int offset, int whence)
{
    return lseek((int)fp->fl_data, offset, whence);
}

static int mockfs_op_sync(struct file *fp)
{
    return fsync((int)fp->fl_data);
}

static int mockfs_op_stat(struct mount_point *mp, const char *path, struct stat *st)
{
    return stat(path, st);
}

static int mockfs_op_unlink(struct mount_point *mp, const char *path)
{
    return unlink(path);
}

static int mockfs_op_rename(struct mount_point *mp, const char *from, const char *to)
{
    return rename(from, to);
}

static int mockfs_op_mkdir(struct mount_point *mp, const char *path, int mode)
{
    return mkdir(path, mode);
}

static int mockfs_op_rmdir(struct mount_point *mp, const char *path)
{
    return rmdir(path);
}

static int mockfs_op_opendir(struct mount_point *mp, struct dir *dp, const char *path)
{
    DIR *d = opendir(path);
    if (d == NULL) {
        return -1;
    }
    dp->dr_data = (uintptr_t)d;

    return 0;
}

static int mockfs_op_readdir(struct mount_point *mp, struct dir *dp, struct dirent *de)
{
    DIR *d = (DIR *)dp->dr_data;
    struct dirent *de_temp = NULL;

    de_temp = readdir(d);
    if (de_temp == NULL) {
        return -1;
    }
    *de = *de_temp;

    return 0;
}

static int mockfs_op_closedir(struct mount_point *mp, struct dir *dp)
{
    DIR *d = (DIR *)dp->dr_data;

    return closedir(d);
}

static int mockfs_op_mount(struct mount_point *mp, va_list valist)
{
    return 0;
}

static int mockfs_op_unmount(struct mount_point *mp, va_list valist)
{
    return 0;
}

static const struct f_ops mockfs_fops = {
    .open = mockfs_op_open,
    .close = mockfs_op_close,
    .read = mockfs_op_read,
    .write = mockfs_op_write,
    .lseek = mockfs_op_lseek,
    .sync = mockfs_op_sync,
};

static const struct m_ops mockfs_mops = {
    .stat = mockfs_op_stat,
    .unlink = mockfs_op_unlink,
    .rename = mockfs_op_rename,
    .mkdir = mockfs_op_mkdir,
    .rmdir = mockfs_op_rmdir,
    .opendir = mockfs_op_opendir,
    .readdir = mockfs_op_readdir,
    .closedir = mockfs_op_closedir,
    .mount = mockfs_op_mount,
    .unmount = mockfs_op_unmount,
};

static struct file_system mockfs_fs = {
    "mockfs",
    &mockfs_fops,
    &mockfs_mops,
};

int mockfs_init(void)
{
    if (vfs_fs_register(&mockfs_fs) != 0) {
        return -1;
    }
    return 0;
}

int mockfs_exit(void)
{
    if (vfs_fs_unregister(&mockfs_fs) != 0) {
        return -1;
    }
    return 0;
}

int mockfs_mount(const char *path)
{
    int ret = vfs_mount("mockfs", path);
    return ret;
}

int mockfs_unmount(const char *path)
{
    int ret = vfs_unmount(path);
    return ret;
}
